﻿/**

 * Copyright (c) 2015-2016, FastDev 刘强 (fastdev@163.com).

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

using OF.DistributeService.Core.Attribute;
using OF.DistributeService.Core.Client;
using OF.DistributeService.Core.Client.Entity;
using OF.DistributeService.Core.Common;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ZooKeeperNet;

namespace OF.DistributeService.Core.Entity
{
    public class ClientConfig : ConfigurationSection
    {
        /// <summary>
        /// 应用名
        /// </summary>
        [ConfigurationProperty("AppName", IsRequired = true)]
        public string AppName
        {
            get { return (string)this["AppName"]; }
            set { this["AppName"] = value; }
        }

        /// <summary>
        /// 分组名
        /// </summary>
        [ConfigurationProperty("GroupName", IsRequired = true)]
        public string GroupName
        {
            get { return (string)this["GroupName"]; }
            set { this["GroupName"] = value; }
        }

        [ConfigurationProperty("ZookeeperHostPort", IsRequired = true)]
        public string ZookeeperHostPort
        {
            get { return (string)this["ZookeeperHostPort"]; }
            set { this["ZookeeperHostPort"] = value; }
        }

        [ConfigurationProperty("ZookeeperSessionTimeSpan", IsRequired = true)]
        public int ZookeeperSessionTimeSpan
        {
            get { return (int)this["ZookeeperSessionTimeSpan"]; }
            set { this["ZookeeperSessionTimeSpan"] = value; }
        }

        [ConfigurationProperty("OFDistributeServiceZKRootPath", IsRequired = true)]
        public string OFDistributeServiceZKRootPath
        {
            get { return (string)this["OFDistributeServiceZKRootPath"]; }
            set { this["OFDistributeServiceZKRootPath"] = value; }
        }

        [ConfigurationProperty("CheckServiceOnlineInterval", IsRequired = true)]
        public int CheckServiceOnlineInterval
        {
            get { return (int)this["CheckServiceOnlineInterval"]; }
            set { this["CheckServiceOnlineInterval"] = value; }
        }

        [ConfigurationProperty("MaxCheckOnlineFailedCount", IsRequired = true)]
        public int MaxCheckOnlineFailedCount
        {
            get { return (int)this["MaxCheckOnlineFailedCount"]; }
            set { this["MaxCheckOnlineFailedCount"] = value; }
        }

        [ConfigurationProperty("MaxFailedIdleCount", IsRequired = true)]
        public int MaxFailedIdleCount
        {
            get { return (int)this["MaxFailedIdleCount"]; }
            set { this["MaxFailedIdleCount"] = value; }
        }

        [ConfigurationProperty("CheckServiceOnlineTimeout", IsRequired = true)]
        public int CheckServiceOnlineTimeout
        {
            get { return (int)this["CheckServiceOnlineTimeout"]; }
            set { this["CheckServiceOnlineTimeout"] = value; }
        }


        private static ClientConfig config = null;
        static ClientConfig()
        {
            config = ConfigurationManager.GetSection("ClientConfig") as ClientConfig;
        }

        public static ClientConfig Get()
        {
            return config;
        }
    }

    public class ClientToAppServiceMeta
    {
        public ClientConfig ClientConfig;
        public ClientToAppConfig ClientToAppConfig;
        public ClientToAppServiceConfig ClientToAppServiceConfig;
        public InvokerGetter InvokerGetter;
    }
    
    public class InvokerGetter
    {
        private object invoker = null;

        private ClientToAppServiceMeta clientToAppServiceMeta = null;
        private ICommonApiCallProxy commonApiCallProxyProvider = null;
        private Type interfaceType = null;
        private EmitHelper emitHelper = null;
        public InvokerGetter(EmitHelper emitHelper,
            ClientToAppServiceMeta clientToAppServiceMeta,
            ICommonApiCallProxy commonApiCallProxyProvider,
            Type interfaceType)
        {
            this.emitHelper = emitHelper;
            this.clientToAppServiceMeta = clientToAppServiceMeta;
            this.commonApiCallProxyProvider = commonApiCallProxyProvider;
            this.interfaceType = interfaceType;
        }

        public object GetInvoker()
        {
            if (invoker == null)
            {
                lock (emitHelper)
                {
                    if (invoker == null)
                    {
                        invoker = emitHelper.GetAPIProxy(clientToAppServiceMeta, commonApiCallProxyProvider, interfaceType);
                       
                        clientToAppServiceMeta = null;
                        commonApiCallProxyProvider = null;
                        interfaceType = null;
                        emitHelper = null;
                    }
                }
            }
            return invoker;
        }
    }

    public class ClientToAppConfig
    {
        /// <summary>
        /// 调用的服务端的app名，同服务端 AppConfig 中的 ApplicationName 保持一致
        /// </summary>
        public string ServiceAppName
        { get; set; }

        //interface transalate params
        public IList<ClientToAppServiceConfig> ServiceList
        { get; set; }
    }

    public class ClientToAppServiceConfig
    {
        /// <summary>
        /// service 接口类型
        /// </summary>
        public Type InterfaceType
        { get; set; }

        /// <summary>
        /// service 在服务端的命名，同服务端 OFDistributeService特性中的 ServiceName保持一致
        /// </summary>
        public string ServiceName
        { get; set; }

        /// <summary>
        /// 版本号
        /// </summary>
        public string Version
        { get; set; }

        private MethodWithHttpMethod[] methodArray;
        public void SetMethodArray(MethodWithHttpMethod[] methodArray)
        {
            this.methodArray = methodArray;
        }

        public MethodWithHttpMethod[] GetMethodArray()
        {
            return this.methodArray;
        }

        private string virtualPath;
        public void SetVirtualPath(string virtualPath)
        {
            this.virtualPath = virtualPath;
        }

        public string GetVirtualPath()
        {
            return this.virtualPath;
        }
    }
}